package hr.eon.client;

import hr.eon.client.ClientConstants.ConnectionStatus;
import hr.eon.client.model.User;
import hr.eon.core.Constants;
import hr.eon.core.EonMessage;
import org.apache.log4j.Logger;
import org.apache.pivot.beans.BXMLSerializer;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;

/**
 * Context class which is wrapper around Spring Application Context.
 * It setup spring context on start and offer method for sending JMS messages.
 * Additionally offers loader for getting JMS messages handlers depending on
 * received message class type.
 * 
 * @author mjovanovic
 * @since 0.0.1
 */
public final class EonContext {

    private EonContext() {}

    private static final Logger LOGGER = Logger.getLogger( EonContext.class );

    private static ClassPathXmlApplicationContext appCtx;
    private static JmsTemplate jmsTemplate;

    private static ConnectionStatus status;

    private static User user;
    private static BXMLSerializer bxmlSerializer;

    static {
        user = new User();
    }

    public static void setup() {
        LOGGER.info( "Starting Eon context.." );
        try {
            appCtx = new ClassPathXmlApplicationContext( "classpath:appCtx.xml" );
            jmsTemplate = (JmsTemplate) appCtx.getBean( "jmsTemplate" );

            LOGGER.info( "Eon context started." );
            status = ConnectionStatus.CONNECTED;
        }
        catch ( ApplicationContextException ace ) {
            if ( ace.getRootCause().getMessage().startsWith( "Connection refused" ) ) {
                LOGGER.info( "Master server is offline." );
                status = ConnectionStatus.MASTER_OFFLINE;
            } else {
                LOGGER.error( "Cannot connect to master server.", ace );
                status = ConnectionStatus.DISCONNECTED;
            }
        }
    }

    public static boolean isServerAlive() {
        if ( status.equals( ConnectionStatus.MASTER_OFFLINE ) || status.equals( ConnectionStatus.DISCONNECTED ) ) {
            return false;
        } else {
            return true;
        }
    }

    public static void setStatus( ConnectionStatus newStatus ) {
        status = newStatus;
    }

    public static void setSerializer( BXMLSerializer serializer ) {
        bxmlSerializer = serializer;
    }

    public static BXMLSerializer getSerializer() {
        return bxmlSerializer;
    }

    public static ConnectionStatus getStatus() {
        return status;
    }

    public static Object getBean( String name ) {
        return appCtx.getBean( name );
    }

    public static Object getBean( Class<?> clazz ) {
        return appCtx.getBean( clazz );
    }

    public static Object getMessageHandler( Class<?> clazz ) {
        return getBean( getHandlerName( clazz.getSimpleName() ) );
    }

    private static String getHandlerName( String message ) {
        char newFirst = (char) ( message.charAt( 0 ) + 32 );
        return new StringBuilder().append( newFirst ).append( message.substring( 1 ) ).append( "Handler" ).toString();
    }

    public static User getUser() {
        return user;
    }

    public static void sendMessage( EonMessage message ) {
        boolean shouldSend = false;
        // Dozvoliti slanje samo Login poruka dok sesija nije kreirana
        // Kad se sesija kreira zabraniti slanje Login poruke
        if ( EonContext.getUser().getSessionToken() == null ) {
            if ( message.getId() == Constants.Messages.LOGIN.getCode() ) {
                shouldSend = true;
            }
        } else {
            if ( message.getId() != Constants.Messages.LOGIN.getCode() ) {
                shouldSend = true;
            }
        }

        if ( shouldSend ) {
            jmsTemplate.convertAndSend( message );
        } else {
            LOGGER.warn( "Trying to send " + message + " while session in invalid state!" );
        }
    }

}
